package com.girant.logger.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.girant.dict.api.DictApi;
import com.girant.dict.entity.dto.SysDictItemDTO;
import com.girant.log.enums.LogCategoryEnums;
import com.girant.logger.config.BoostConfig;
import com.girant.logger.entity.domain.LogDocumentDO;
import com.girant.logger.entity.dto.BusinessLogDTO;
import com.girant.logger.entity.dto.BusinessLogExportDTO;
import com.girant.logger.entity.dto.ErrorLogDTO;
import com.girant.logger.entity.vo.show.LogExportVO;
import com.girant.logger.mapper.LogMapper;
import com.girant.logger.service.LogExportService;
import com.girant.logger.utils.SearchUtil;
import com.girant.model.enums.ClientTypeEnums;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import static com.girant.logger.utils.SearchUtil.getEnumLabel;
import static com.girant.logger.config.Constants.DICT_CODE_SERVER;
@Slf4j
@Service
public class LogExportServiceImpl implements LogExportService {
    @Autowired
    private LogMapper logMapper;

    @Autowired
    private DictApi dictApi;

    @Autowired
    private BoostConfig boostConfig;

    @Value("${es.min.score:0.2}")
    private Double minScore;


    @Override
    public List<LogExportVO> exportLog(BusinessLogExportDTO request) throws IOException {
        // 1. 构建查询条件
        LambdaEsQueryWrapper<LogDocumentDO> wrapper = buildBoolQuery(request);
        wrapper.orderByDesc(LogDocumentDO::getOperationTime);

        if (StrUtil.isNotBlank(request.getKeyword())){
            wrapper.minScore(minScore);
        }


        // 2. 查询ES
        List<LogDocumentDO> documents = logMapper.selectList(wrapper);
        log.info("ES查询返回结果数量: {}", documents.size());

        // 3. 批量处理字典标签（先收集所有key，再批量查询）
        List<SysDictItemDTO> list = dictApi.getDictList(DICT_CODE_SERVER);
        Map<String, String> map = list.stream().collect(Collectors.toMap(SysDictItemDTO::getDictKey, SysDictItemDTO::getDictLabel));

        // 4. 转换为VO
        return documents.stream()
                .map(document -> convertToVO(document, map))
                .collect(Collectors.toList());
    }

    private LogExportVO convertToVO(LogDocumentDO document, Map<String, String> serverLabels) {
        LogExportVO vo = BeanUtil.copyProperties(document, LogExportVO.class);

        // 处理客户端类型枚举
        vo.setClientTypeLabel(getEnumLabel(
                ClientTypeEnums.values(),
                document.getClientType(),
                ClientTypeEnums::getValue,
                ClientTypeEnums::getLabel
        ));

        // 处理业务分类枚举
        vo.setCategoryLabel(getEnumLabel(
                LogCategoryEnums.values(),
                document.getCategory(),
                LogCategoryEnums::getValue,
                LogCategoryEnums::getLabel
        ));

        // 设置字典标签
        vo.setServerNameLabel(
                serverLabels.getOrDefault(document.getServerName(), "")
        );

        return vo;
    }

    /**
     * 构建ES查询条件
     */
    private LambdaEsQueryWrapper<LogDocumentDO> buildBoolQuery(BusinessLogExportDTO request) {
        //构建查询条件
        LambdaEsQueryWrapper<LogDocumentDO> wrapper = new LambdaEsQueryWrapper<>();

        if (ObjectUtil.isNotEmpty(request.getOperationStartTime())) {
            wrapper.ge(LogDocumentDO::getOperationTime, DateUtil.format(request.getOperationStartTime(), DatePattern.NORM_DATETIME_MS_PATTERN));//大于等于，并且转化格式
        }
        // 处理结束时间
        if (ObjectUtil.isNotEmpty(request.getOperationEndTime())) {
            wrapper.le(LogDocumentDO::getOperationTime, DateUtil.format(request.getOperationEndTime(), DatePattern.NORM_DATETIME_MS_PATTERN));//小于等于，并且转化格式
        }

        // 2. IP模糊匹配（CIDR格式）
        if (StrUtil.isNotBlank(request.getSourceIp())) {
            String cidr = SearchUtil.convertIpPrefixToCidr(request.getSourceIp());
            wrapper.eq(LogDocumentDO::getSourceIp, cidr);
        }

        // 3. 精确匹配TraceId,SpanId字段
        if (StrUtil.isNotBlank(request.getTraceId())) {
            wrapper.eq(LogDocumentDO::getTraceId, request.getTraceId());
        }
        if (StrUtil.isNotBlank(request.getSpanId())) {
            wrapper.eq(LogDocumentDO::getSpanId, request.getSpanId());
        }
        if (StrUtil.isNotBlank(request.getServerName())) {
            wrapper.eq(LogDocumentDO::getServerName, request.getServerName());
        }

        if (StrUtil.isNotBlank(request.getClientType())) {//补充
            wrapper.eq(LogDocumentDO::getClientType, request.getClientType());
        }

        if (StrUtil.isNotBlank(request.getCategory())) {//补充
            wrapper.eq(LogDocumentDO::getCategory, request.getCategory());
        }

        if (StrUtil.isNotBlank(request.getLogLevel())) {//补充
            wrapper.eq(LogDocumentDO::getLogLevel, request.getLogLevel());
        }

        if (StrUtil.isNotBlank(request.getKeyword())) {
            wrapper.should(w -> w.match(LogDocumentDO::getTitle, request.getKeyword(), boostConfig.getErrorInfo()));
            wrapper.should(w -> w.match(LogDocumentDO::getContent, request.getKeyword(), boostConfig.getContent()));
            wrapper.should(w -> w.eq(LogDocumentDO::getOperationNickname, request.getKeyword(), boostConfig.getOperationNickname()));
            wrapper.should(w -> w.eq(LogDocumentDO::getClientVersion, request.getKeyword(), boostConfig.getClientVersion()));
            wrapper.should(w -> w.eq(LogDocumentDO::getStackTrace, request.getKeyword(), boostConfig.getStackTrace()));
            wrapper.should(w -> w.match(LogDocumentDO::getRequestParams, request.getKeyword(), boostConfig.getRequestParams()));
            wrapper.should(w -> w.match(LogDocumentDO::getClientBrowser, request.getKeyword(), boostConfig.getClientBrowser()));
        }
        return wrapper;
    }


}
